﻿#include "Type.h"

#include "StringSerializable.h"
#include "TypeInstance.h"
#include "PlaceholderInfo.h"
#include "FunctionList.h"
#include "PropertyList.h"

#include "Function.h"
#include "Property.h"


void CType::SetBaseType(CType *InBaseType)
{
    assert(BaseType==nullptr && "Base type already set" );
    BaseType=InBaseType;
    if(BaseType)
    {
        BaseType->DerivedTypes.Add(this);
    }

}

TMap<CString /* class name */, CType *> &CType::GetAllTypes()
{
    static TMap<CString /* class name */, CType*> AllTypees(1024);
    return AllTypees;
}

CType* CType::FindType(const CString& InTypeName)
{
    if(GetAllTypes().Contains(InTypeName))
    {
        return GetAllTypes()[InTypeName];
    }

    return nullptr;

}

CTypeTable &CType::GetTypeTable()
{
    static CTypeTable Table = CTypeTable();
    return Table;
}

CType *CType::FindType(STypeID InTypeID)
{
    if(!InTypeID.IsValid())
    {
        return nullptr;
    }
    
    return GetTypeTable().FindType(InTypeID);
}

CFunction *CType::FindFunction(const CString &InFunctionName)
{
    if(Functions)
    {
        return Functions->FindFunction(InFunctionName);
    }
    return nullptr;
}

CFunction *CType::FindNativeFunction(int64_t NativeFunctionPtr)
{
    if(Functions)
    {
        return Functions->FindNativeFunction(NativeFunctionPtr);
    }
    return nullptr;
}

bool CType::IsDependsOnEditor()
{
    if(IsGeneralizedType())
    {
        if(GeneralizedInfo->TemplateType->IsDependsOnEditor())
        {
            return true;
        }

        for(auto Type:GeneralizedInfo->TypeArguments)
        {
            if(Type->IsDependsOnEditor())
            {
                return true;
            }
        }
    }
    else
    {
        return GetFullName().StartsWith(GetEngineEditorNamespace());
    }

    return false;
}


CProperty *CType::FindProperty(const CString &InPropertyName)
{
    if(Properties)
    {
        return Properties->FindProperty(InPropertyName);
    }
    return nullptr;
}

CNativeFieldProperty *CType::FindNativeFieldPropertyByOffset(int64_t Offset)
{
    if(Properties)
    {
        return Properties->FindNativeFieldPropertyByOffset(Offset);
    }
    return nullptr;
}

CType::CType(STypeID InID
    ,ETypeFlags InFlags)
{
    ID=InID;

    Flags=InFlags;
    // assert(InParentNameScope!=nullptr);
    // ParentNameScope=InParentNameScope;
    // ParentNameScope->AddSubType(this);
    // {
    //     TVector<CString> NameScopeID=ParentNameScope->GetNameScopeID();
    //     NameScopeID.Add(Name);
    //     NameScope=new CNameScope(CNameScope::EType::Class,NameScopeID);
    //     ParentNameScope->AddSubNameScope(NameScope);
    // }

    GetAllTypes().Add(ID.GetTypeFullName(),this);
    GetTypeTable().AddType(this,ID);
}

CType::~CType()
{
    GetAllTypes().Remove(GetFullName());

    if(Functions)
    {
        delete Functions;
    }

    if(Properties)
    {
        delete Properties;
    }
}

CString CType::GetEngineCoreNamespace()
{
    static CString NamespaceName = U"EngineCore";
    return NamespaceName;
}

CString CType::GetEngineEditorNamespace()
{
    static CString NamespaceName = U"EngineEditor";
    return NamespaceName;
}


CString CType::GetFullName() const
{
    return ID.GetTypeFullName();
}

CString CType::GetShortName() const
{
    auto Index=GetFullName().FindLast(U"::");
    if(Index==-1)
    {
        return GetFullName();
    }
    else
    {
        return GetFullName().SubString(Index+2);
    }
}

uint32_t CType::GetSize() const
{
    assert(CanHaveInstance() && "This type can not have instance");


    return Instancable->GetSize();
}

void *CType::CreateInstance()
{
    assert(CanHaveInstance() && "This type can not have instance");
    return Instancable->CreateInstance();
}

void CType::InitInstance(void *Memory)
{
    assert(CanHaveInstance() && "This type can not have instance");
    Instancable->InitInstance(Memory);
}

void CType::EraseInstance(void *Instance)
{
    assert(CanHaveInstance() && "This type can not have instance");
    Instancable->EraseInstance(Instance);
}

void *CType::CloneInstance(const void *Instance)
{
    //allocate memory
    void* Memory=malloc(GetSize());
    CloneInstance(Instance,Memory);
    return Memory;
}

void CType::CloneInstance(const void *Instance, void *TargetMemory)
{
    assert(CanHaveInstance() && "This type can not have instance");
    Instancable->CloneInstance(Instance,TargetMemory);
}

uint64_t CType::GetInstanceHash(const void *Instance) const
{
    assert(CanHaveInstance() && "This type can not have instance");
    return Instancable->GetInstanceHash(Instance);
}

bool CType::IsInstanceEqual(const void *Instance0, const void *Instance1) const
{
    assert(CanHaveInstance() && "This type can not have instance");
    return Instancable->IsInstanceEqual(Instance0,Instance1);
}

CString CType::ToDebugString(const void *Instance) const
{
    assert(CanHaveInstance() && "This type can not have instance");
    return Instancable->ToDebugString(Instance);
}

int64_t CType::GetDebugNamedChildNum(const void *Instance) const
{
    assert(CanHaveInstance() && "This type can not have instance");
    return Instancable->GetDebugNamedChildNum(Instance);
}

CType *CType::GetDebugNamedChildType(int64_t Index, const void *Instance) const
{
    assert(CanHaveInstance() && "This type can not have instance");
    return Instancable->GetDebugNamedChildType(Index,Instance);
}

CString CType::GetDebugNamedChildName(int64_t Index, const void *Instance) const
{
    assert(CanHaveInstance() && "This type can not have instance");
    return Instancable->GetDebugNamedChildName(Index,Instance);
}

const void *CType::GetDebugNamedChildValue(int64_t Index, const void *Instance) const
{
    assert(CanHaveInstance() && "This type can not have instance");
    return Instancable->GetDebugNamedChildValue(Index,Instance);
}

int64_t CType::GetDebugIndexedChildNum(const void *Instance) const
{
    assert(CanHaveInstance() && "This type can not have instance");
    return Instancable->GetDebugIndexedChildNum(Instance);
}

CType *CType::GetDebugIndexedChildType(int64_t Index, const void *Instance) const
{
    assert(CanHaveInstance() && "This type can not have instance");
    return Instancable->GetDebugIndexedChildType(Index,Instance);
}

const void *CType::GetDebugIndexedChildValue(int64_t Index, const void *Instance) const
{
    assert(CanHaveInstance() && "This type can not have instance");
    return Instancable->GetDebugIndexedChildValue(Index,Instance);
}

void CType::ResetAllocated(void *Memory)
{
    assert(CanHaveInstance() && "This type can not have instance");
    Instancable->ResetAllocated(Memory);
}
bool CType::IsForceConvertableTo(CType * Other)
{
    assert(CanHaveInstance() && "This type can not have instance");
    if(Other==this)
    {
        return true;
    }
    return Instancable->IsForceConvertableTo(Other);
}

bool CType::IsListPlaceholderType() const
{
    return IsGenericPlaceholderType() && PlaceholderInfo->bIsList;
}

CString CType::SerializeToString(const void *Instance) const
{
    assert(IsStringSerializable() && "This type is not string serializable");
    return StringSerializable->ToString(Instance);
}

void CType::DeserializeFromString(const CString &String, void *Instance) const
{
    assert(IsStringSerializable() && "This type is not string serializable");
    StringSerializable->FromString(String,Instance);
}
